﻿using mvcForum.Core.Abstractions.Interfaces;
using mvcForum.Core.Abstractions.Interfaces.DependencyManagement;
using mvcForum.Core.Interfaces.Services;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace mvcForum.Web {

	public class KnownTypeHolder : IKnownTypeHolder {
		private readonly ILogger logger;

		public KnownTypeHolder(ILogger logger) {
			this.logger = logger;
			this.ShadowCopy();
		}

		/// <summary>
		/// Method for copying all the assemblies into another folder, so we can load them without locking any files
		/// and blocking for overriding the assemblies in the bin folder.
		/// </summary>
		protected virtual void ShadowCopy() {
			// Get the full filesystem path to the /bin folder.
			//String binPath = HttpContext.Current.Server.MapPath("/bin");
			//// Get a filesystem path to the shadow copy folder.
			//String shadowPath = HttpContext.Current.Server.MapPath("/.shadowbin");
			//try {
			//    // Does the shadow copy folder already exist?
			//    if (Directory.Exists(shadowPath)) {
			//        // Let's delete it, it's a left-over from last time we probed.
			//        Directory.Delete(shadowPath, true);
			//    }
			//    // Create the shadow copy folder.
			//    Directory.CreateDirectory(shadowPath);

			//    // Iterate all DLL files in the /bin folder.
			//    foreach (var file in Directory.GetFiles(binPath, "*.dll")) {
			//        // Copy the file to the shadow copy folder.
			//        File.Copy(file, String.Format("{0}\\{1}", shadowPath, Path.GetFileName(file)));
			//    }
			//}
			//catch { }

			// Iterate all the DLL files in the shadow copy folder.
			//foreach (var file in Directory.GetFiles(shadowPath, "*.dll")) {
			//foreach (var file in Directory.GetFiles(binPath, "*.dll")) {
			//    // Load the assembly.
			//    Assembly ass = Assembly.LoadFile(file);
			//    // Probe it!
			//    this.ProbeAssembly(ass);
			//}

			// Iterate the assemblies in the current app domain!
			foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) {
				logger.Log(EventType.Info, String.Format("About to probe {0}", assembly.FullName));
				// Probe it!
				this.ProbeAssembly(assembly);
			}
		}

		protected virtual void ProbeAssembly(Assembly ass) {
			try {
				// Iterate all types in the assembly.
				foreach (var type in ass.GetTypes()) {
					//logger.Log(EventType.Info, String.Format("Looking at type {0}", type));
					// A class implementing the IBootStrapper interface?
					if (type.GetInterface("IBootStrapper") != null) {
						logger.Log(EventType.Info, String.Format("Found a bootstrapper {0}", type));
						// Let's put it in the BootStrapper collection.
						//strappers.Add((IBootStrapper)Activator.CreateInstance(type));
					}
					// A class implementing the IInstaller interface?
					if (type.GetInterface("IInstaller") != null) {
						logger.Log(EventType.Info, String.Format("Found an installer {0}", type));
						// Let's put it in the Installer collection.
						installers.Add((IInstaller)Activator.CreateInstance(type));
					}
				}
			}
			catch (Exception ex) {
				// Something failed, let's log it!
				logger.Log(EventType.Error, String.Format("ProbeAssembly failed, {1}", ass, ass.FullName), ex);
			}
		}

		private List<IInstaller> installers = new List<IInstaller>();
		public virtual IEnumerable<IInstaller> Installers {
			get {
				return this.installers;
			}
		}

		//private List<IBootStrapper> strappers = new List<IBootStrapper>();
		//public virtual IEnumerable<IBootStrapper> Bootstrappers {
		//    get {
		//        return this.strappers;
		//    }
		//}
	}
}